package dfsketches.gr3d;

public class Matrix3D {

	public float m11;
	public float m12;
	public float m13;
	public float m14;
	public float m21;
	public float m22;
	public float m23;
	public float m24;
	public float m31;
	public float m32;
	public float m33;
	public float m34;
	
	public Matrix3D() {
		m11 = 0f;
		m12 = 0f;
		m13 = 0f;
		m14 = 0f;
		m21 = 0f;
		m22 = 0f;
		m23 = 0f;
		m24 = 0f;
		m31 = 0f;
		m32 = 0f;
		m33 = 0f;
		m34 = 0f;
	}

	public Matrix3D(float m11, float m12, float m13, float m14, float m21,
			float m22, float m23, float m24, float m31, float m32, float m33,
			float m34) {
		this.m11 = m11;
		this.m12 = m12;
		this.m13 = m13;
		this.m14 = m14;
		this.m21 = m21;
		this.m22 = m22;
		this.m23 = m23;
		this.m24 = m24;
		this.m31 = m31;
		this.m32 = m32;
		this.m33 = m33;
		this.m34 = m34;
	}
	
	public Matrix3D(Matrix3D m) {
		this.m11 = m.m11;
		this.m12 = m.m12;
		this.m13 = m.m13;
		this.m14 = m.m14;
		this.m21 = m.m21;
		this.m22 = m.m22;
		this.m23 = m.m23;
		this.m24 = m.m24;
		this.m31 = m.m31;
		this.m32 = m.m32;
		this.m33 = m.m33;
		this.m34 = m.m34;
	}

	public static Matrix3D getZeroMatrix() {
		return new Matrix3D();
	}
	
	public static Matrix3D getUniteMatrix() {
		return (new Matrix3D()).makeUnite();
	}
	
	public static Matrix3D getTranslationMatrix(float tx, float ty, float tz) {
		return (new Matrix3D()).makeTranslation(tx, ty, tz);
	}
	
	public static Matrix3D getRotationXMatrix(float angle) {
		float cos = (float) Math.cos(angle);
		float sin = (float) Math.sin(angle);
		return new Matrix3D(
				1f,  0f,  0f, 0f,
				0f, cos,-sin, 0f,
				0f, sin, cos, 0f
				);
	}
	
	public static Matrix3D getRotationYMatrix(float angle) {
		float cos = (float) Math.cos(angle);
		float sin = (float) Math.sin(angle);
		return new Matrix3D(
				 cos,  0f, sin, 0f,
				  0f,  1f,  0f, 0f,
				-sin,  0f, cos, 0f
				);
	}
	
	public static Matrix3D getRotationZMatrix(float angle) {
		float cos = (float) Math.cos(angle);
		float sin = (float) Math.sin(angle);
		return new Matrix3D(
				cos,-sin, 0f, 0f,
				sin, cos, 0f, 0f,
				 0f,  0f, 1f, 0f
				);
	}
	
	public static Matrix3D getScaleMatrix(float sx, float sy, float sz) {
		return new Matrix3D(
				sx, 0f, 0f, 0f,
				0f, sy, 0f, 0f,
				0f, 0f, sz, 0f
		);
	}
	
	public static Matrix3D getPolarScaleMatrix(float sx, float sy, float sz,
			float x, float y, float z) {
		return new Matrix3D(
				sx, 0, 0, x * (1 - sx),
				0, sy, 0, y * (1 - sy),
				0, 0, sz, z * (1 - sz)
				);
	}
	
	public static Matrix3D getPolarRotationXMatrix(float angle,
			float y, float z) {
		float cos = (float)Math.cos(angle);
		float sin = (float)Math.sin(angle);
		float cos1 = 1 - cos;
		return new Matrix3D(
				1f,  0f,   0f,                 0f,
				0f, cos, -sin, y * cos1 + y * sin,
				0f, sin,  cos, z * cos1 - z * sin
				);
	}

	public static Matrix3D getPolarRotationYMatrix(float angle,
			float x, float z) {
		float cos = (float)Math.cos(angle);
		float sin = (float)Math.sin(angle);
		float cos1 = 1 - cos;
		return new Matrix3D(
				 cos,   0f, sin, x * cos1 - z * sin,
				  0f,   1f,  0f,                 0f,
				-sin,   0f, cos, z * cos1 + x * sin
				);
	}
	
	public static Matrix3D getPolarRotationZMatrix(float angle,
			float x, float y) {
		float cos = (float)Math.cos(angle);
		float sin = (float)Math.sin(angle);
		float cos1 = 1 - cos;
		return new Matrix3D(
				cos, -sin, 0f, x * cos1 + y * sin,
				sin,  cos, 0f, y * cos1 - x * sin,
				 0f,   0f, 1f, 0
				);
	}
	
//	public static Matrix3D getAxisRotationMatrix(float bx, float by, float bz,
//			float dx, float dy, float dz, float angle) {
//		float cos = (float)Math.cos(angle);
//		float sin = (float)Math.sin(angle);
//		float cos1 = 1 - cos;
//		return new Matrix3D(
//				cos, -sin, 0f, x * cos1 + y * sin,
//				sin,  cos, 0f, y * cos1 - x * sin,
//				 0f,   0f, 1f, 0
//				);
//	}
	
	public void multiplyRight(Matrix3D m) {
		float t11 = m.m11 * m11 + m.m12 * m21 + m.m13 * m31;
		float t12 = m.m11 * m12 + m.m12 * m22 + m.m13 * m32;
		float t13 = m.m11 * m13 + m.m12 * m23 + m.m13 * m33;
		float t14 = m.m11 * m14 + m.m12 * m24 + m.m13 * m34 + m.m14;
		float t21 = m.m21 * m11 + m.m22 * m21 + m.m23 * m31;
		float t22 = m.m21 * m12 + m.m22 * m22 + m.m23 * m32;
		float t23 = m.m21 * m13 + m.m22 * m23 + m.m23 * m33;
		float t24 = m.m21 * m14 + m.m22 * m24 + m.m23 * m34 + m.m24;
		float t31 = m.m31 * m11 + m.m32 * m21 + m.m33 * m31;
		float t32 = m.m31 * m12 + m.m32 * m22 + m.m33 * m32;
		float t33 = m.m31 * m13 + m.m32 * m23 + m.m33 * m33;
		float t34 = m.m31 * m14 + m.m32 * m24 + m.m33 * m34 + m.m34;
		m11 = t11;
		m12 = t12;
		m13 = t13;
		m14 = t14;
		m21 = t21;
		m22 = t22;
		m23 = t23;
		m24 = t24;
		m31 = t31;
		m32 = t32;
		m33 = t33;
		m34 = t34;
	}
	
	public void multiplyLeft(Matrix3D m) {
		float t11 = m11 * m.m11 + m12 * m.m21 + m13 * m.m31;
		float t12 = m11 * m.m12 + m12 * m.m22 + m13 * m.m32;
		float t13 = m11 * m.m13 + m12 * m.m23 + m13 * m.m33;
		float t14 = m11 * m.m14 + m12 * m.m24 + m13 * m.m34 + m14;
		float t21 = m21 * m.m11 + m22 * m.m21 + m23 * m.m31;
		float t22 = m21 * m.m12 + m22 * m.m22 + m23 * m.m32;
		float t23 = m21 * m.m13 + m22 * m.m23 + m23 * m.m33;
		float t24 = m21 * m.m14 + m22 * m.m24 + m23 * m.m34 + m24;
		float t31 = m31 * m.m11 + m32 * m.m21 + m33 * m.m31;
		float t32 = m31 * m.m12 + m32 * m.m22 + m33 * m.m32;
		float t33 = m31 * m.m13 + m32 * m.m23 + m33 * m.m33;
		float t34 = m31 * m.m14 + m32 * m.m24 + m33 * m.m34 + m34;
		m11 = t11;
		m12 = t12;
		m13 = t13;
		m14 = t14;
		m21 = t21;
		m22 = t22;
		m23 = t23;
		m24 = t24;
		m31 = t31;
		m32 = t32;
		m33 = t33;
		m34 = t34;
	}

	public void copy(Matrix3D m) {
		m11 = m.m11;
		m12 = m.m12;
		m13 = m.m13;
		m14 = m.m14;
		m21 = m.m21;
		m22 = m.m22;
		m23 = m.m23;
		m24 = m.m24;
		m31 = m.m31;
		m32 = m.m32;
		m33 = m.m33;
		m34 = m.m34;
	}

	public Matrix3D makeUnite() {
		m11 = 1f; m12 = 0f; m13 = 0f; m14 = 0f;
		m21 = 0f; m22 = 1f; m23 = 0f; m24 = 0f;
		m31 = 0f; m32 = 0f; m33 = 1f; m34 = 0f;
		return this;
	}

	public Matrix3D makeTranslation(float tx, float ty, float tz) {
		m11 = 1f; m12 = 0f; m13 = 0f; m14 = tx;
		m21 = 0f; m22 = 1f; m23 = 0f; m24 = ty;
		m31 = 0f; m32 = 0f; m33 = 1f; m34 = tz;
		return this;
	}

	public float[][] getFloat() {
		float[][] m = new float[3][4];
		m[0][0] = m11;
		m[0][1] = m12;
		m[0][2] = m13;
		m[0][3] = m14;
		m[1][0] = m21;
		m[1][1] = m22;
		m[1][2] = m23;
		m[1][3] = m24;
		m[2][0] = m31;
		m[2][1] = m32;
		m[2][2] = m33;
		m[2][3] = m34;
		return m;
	}
	
	public Matrix3D reverse() {
		float[][] m = getFloat();
		float[][] r = {
				{1f, 0f, 0f, 0f},
				{0f, 1f, 0f, 0f},
				{0f, 0f, 1f, 0f}
		};
		for (int i = 0; i < 3; i++) {
			float mm1 = Math.abs(m[0][i]);
			float mm2 = Math.abs(m[1][i]);
			float mm3 = Math.abs(m[2][i]);
			float max = mm1;
			int maxn = 0;
			if (max < mm2) maxn = 1;
			if (max < mm3) maxn = 2;
			
			float[] m0;			float[] r0;
			m0 = m[maxn];		r0 = r[maxn];
			m[maxn] = m[0];		r[maxn] = r[0];
			m[0] = m0;			r[0] = r0;
			
			float k = 1f / m[0][i];
			m0[0] *= k;			r0[0] *= k;
			m0[1] *= k;			r0[1] *= k;
			m0[2] *= k;			r0[2] *= k;
			m0[3] *= k;			r0[3] *= k;
			
			float km;
			float[] t;			float[] tr;
			t = m[1];			tr = r[1];
			km = t[i];
			t[0] -= km * m0[0];	tr[0] -= km * r0[0];
			t[1] -= km * m0[1];	tr[1] -= km * r0[1];
			t[2] -= km * m0[2]; tr[2] -= km * r0[2];
			t[3] -= km * m0[3]; tr[3] -= km * r0[3];
			t = m[2];			tr = r[2];
			km = t[i];
			t[0] -= km * m0[0];	tr[0] -= km * r0[0];
			t[1] -= km * m0[1];	tr[1] -= km * r0[1];
			t[2] -= km * m0[2]; tr[2] -= km * r0[2];
			t[3] -= km * m0[3]; tr[3] -= km * r0[3];

			m0 = m[maxn];		r0 = r[maxn];
			m[maxn] = m[0];		r[maxn] = r[0];
			m[0] = m0;			r[0] = r0;
		}
		return new Matrix3D(
				r[0][0], r[0][1], r[0][2], -m[0][3],
				r[1][0], r[1][1], r[1][2], -m[1][3],
				r[2][0], r[2][1], r[2][2], -m[2][3]);
	}
	
}